home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / timecodes / qttimecode / qttimecode.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  19.6 KB  |  732 lines

  1. //////////
  2. //
  3. //    File:        QTTimeCode.c
  4. //
  5. //    Contains:    QuickTime timecode media handler sample code.
  6. //
  7. //    Written by:    Tim Monroe
  8. //                Based on AddTC.c sample code by QT Engineering and Apple Developer Technical Support.
  9. //
  10. //    Copyright:    © 1991-1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <4>         04/07/99    rtm        modified QTTC_AddTimeCodeToMovie to add big-endian time code data to movie
  15. //                                    (fixes problems on Windows)
  16. //       <3>         06/05/98    rtm        fixed track geometry calculations in QTTC_AddTimeCodeToMovie; other minor
  17. //                                    cleanup here and there
  18. //       <2>         05/21/98    rtm        added QTTC_ShowStringToUser
  19. //       <1>         05/18/98    rtm        first file; conversion to personal coding style; updated to latest headers;
  20. //                                    added ability to toggle timecode display in a movie containing a timecode track;
  21. //                                    added ability to extract timecode values and source info; ported to Windows
  22. //     
  23. //    This source code shows how to add a timecode track to a movie. It also shows how to toggle the visibility
  24. //    of a movie's timecode track and how to extract timecode values (and other info) from a timecode track. 
  25. //
  26. //////////
  27.  
  28. // TO DO:
  29. //    Timecode does not display correctly on Windows if starting time is other than 0;
  30. //    saving, closing movie and reopening it corrects the problem; what gives?
  31.  
  32. // header files
  33. #include "QTTimeCode.h"
  34.  
  35. // global variables
  36. Str255                    gSrcName;
  37. Boolean                    gDisplayTimeCode = false;
  38. Boolean                    gDisplayBelowVideo = true;
  39. TimeScale                gTimeScale = 2997;                // typical for NTSC video (29.97 frames/sec)
  40. TimeValue                gFrameDur = 100;                // duration of a single frame
  41. long                    gNumFrames = 30;                // frames per second
  42. Boolean                    gDropFrameVal = true;
  43. Boolean                    g24Hour = true;
  44. Boolean                    gNegOK = false;
  45. Boolean                    gIsNeg = false;
  46. long                    gHours = 0;
  47. long                    gMinutes = 0;
  48. long                    gSeconds = 0;
  49. long                    gFrames = 0;
  50. long                    gCounterVal = 0;
  51. Boolean                    gUseTimeCode = true;
  52.  
  53. extern short             gAppResFile;                    // file reference number for this application's resource file
  54. extern ModalFilterUPP    gModalFilterUPP;                // UPP to our custom dialog event filter
  55.  
  56.  
  57. //////////
  58. //
  59. // QTTC_DeleteTimeCodeTracks
  60. // Remove all existing timecode tracks from the specified movie.
  61. //
  62. //////////
  63.  
  64. void QTTC_DeleteTimeCodeTracks (Movie theMovie)
  65. {
  66.     Track                myTrack = NULL;
  67.     
  68.     myTrack = GetMovieIndTrackType(theMovie, 1, TimeCodeMediaType, movieTrackMediaType);
  69.     while (myTrack != NULL) {
  70.         DisposeMovieTrack(myTrack);
  71.         myTrack = GetMovieIndTrackType(theMovie, 1, TimeCodeMediaType, movieTrackMediaType);
  72.     }
  73. }
  74.  
  75.  
  76. //////////
  77. //
  78. // QTTC_AddTimeCodeToMovie
  79. // Add a timecode track to the specified movie.
  80. //
  81. //////////
  82.  
  83. OSErr QTTC_AddTimeCodeToMovie (Movie theMovie, OSType theType)
  84. {
  85.     Track                myTypeTrack = NULL;
  86.     Track                myTrack = NULL;
  87.     Media                myMedia = NULL;
  88.     MediaHandler        myHandler = NULL;
  89.     TimeCodeDef            myTCDef;
  90.     TimeCodeRecord        myTCRec;
  91.     Str63                myString;
  92.     TimeValue            myDuration;
  93.     MatrixRecord        myMatrix;
  94.     Fixed                myWidth;
  95.     Fixed                myHeight;
  96.     Fixed                myTCHeight;
  97.     long                myFlags = 0L;
  98.     TCTextOptions        myTextOptions;
  99.     FontInfo            myFontInfo;
  100.     OSErr                myErr = noErr;
  101.     
  102.     //////////
  103.     //
  104.     // find the target track
  105.     //
  106.     //////////
  107.  
  108.     // get the (first) track of the specified type; this track determines the width of the new timecode track
  109.     myTypeTrack = GetMovieIndTrackType(theMovie, 1, theType, movieTrackMediaType);
  110.     if (myTypeTrack == NULL) {
  111.         myErr = trackNotInMovie;
  112.         goto bail;
  113.     }
  114.     
  115.     // get the dimensions of the target track
  116.     GetTrackDimensions(myTypeTrack, &myWidth, &myHeight);
  117.     
  118.     //////////
  119.     //
  120.     // create the timecode track and media
  121.     //
  122.     //////////
  123.  
  124.     myTrack = NewMovieTrack(theMovie, myWidth, kTimeCodeTrackSize, kNoVolume);
  125.     myMedia = NewTrackMedia(myTrack, TimeCodeMediaType, GetMovieTimeScale(theMovie), NULL, 0);
  126.     myHandler = GetMediaHandler(myMedia);
  127.     
  128.     //////////
  129.     //
  130.     // fill in a timecode definition structure; this becomes part of the timecode description
  131.     //
  132.     //////////
  133.     
  134.     // set the timecode format information flags
  135.     if (gUseTimeCode) {
  136.         myFlags = 0L;
  137.         if (gDropFrameVal)
  138.             myFlags |= tcDropFrame;
  139.         if (gIsNeg)
  140.             myFlags |= tcNegTimesOK;
  141.         if (g24Hour)
  142.             myFlags |= tc24HourMax;
  143.         
  144.     } else {
  145.         myFlags = tcCounter;
  146.     }
  147.     
  148.     myTCDef.flags = myFlags;
  149.     myTCDef.fTimeScale = gTimeScale;
  150.     myTCDef.frameDuration = gFrameDur;
  151.     myTCDef.numFrames = gNumFrames;
  152.  
  153.     //////////
  154.     //
  155.     // fill in a timecode record
  156.     //
  157.     //////////
  158.     
  159.     if (gUseTimeCode) {
  160.         myTCRec.t.hours = (UInt8)gHours;
  161.         myTCRec.t.minutes = (UInt8)gMinutes;        // negative flag is here
  162.         myTCRec.t.seconds = (UInt8)gSeconds;
  163.         myTCRec.t.frames = (UInt8)gFrames;
  164.         if (gIsNeg)
  165.             myTCRec.t.minutes |= tctNegFlag;
  166.     } else {
  167.         myTCRec.c.counter = gCounterVal;
  168.     }
  169.  
  170.     //////////
  171.     //
  172.     // figure out the timecode track geometry
  173.     //
  174.     //////////
  175.     
  176.     // get display options to calculate box height
  177.     TCGetDisplayOptions(myHandler, &myTextOptions);
  178.     
  179.     // use the starting time to figure out the dimensions of track    
  180.     TCTimeCodeToString(myHandler, &myTCDef, &myTCRec, myString);
  181.     TextFont(myTextOptions.txFont);
  182.     TextFace(myTextOptions.txFace);
  183.     TextSize(myTextOptions.txSize);
  184.     GetFontInfo(&myFontInfo);
  185.     
  186.     // calculate track width and height based on text    
  187.     myTCHeight = FixRatio(myFontInfo.ascent + myFontInfo.descent + 2, 1);
  188.  
  189.     GetTrackMatrix(myTrack, &myMatrix);
  190.     if (gDisplayBelowVideo) {
  191.         SetTrackDimensions(myTrack, myWidth, myTCHeight);
  192.         TranslateMatrix(&myMatrix, 0, myHeight);
  193.     }
  194.     
  195.     SetTrackMatrix(myTrack, &myMatrix);    
  196.     SetTrackEnabled(myTrack, gDisplayTimeCode ? true : false);
  197.         
  198.     TCSetTimeCodeFlags(myHandler, gDisplayTimeCode ? tcdfShowTimeCode : 0, tcdfShowTimeCode);
  199.     
  200.     //////////
  201.     //
  202.     // edit the track media
  203.     //
  204.     //////////
  205.  
  206.     myErr = BeginMediaEdits(myMedia);    
  207.     if (myErr == noErr) {
  208.         TimeCodeDescriptionHandle            myDesc = NULL;
  209.         long                                **myFrameHandle;
  210.         long                                mySize;
  211.         UserData                            myUserData;
  212.         
  213.         //////////
  214.         //
  215.         // create and configure a new timecode description handle
  216.         //
  217.         //////////
  218.  
  219.         mySize = sizeof(TimeCodeDescription);
  220.         myDesc = (TimeCodeDescriptionHandle)NewHandleClear(mySize);
  221.         if (myDesc == NULL)
  222.             goto bail;
  223.         
  224.         (**myDesc).descSize = mySize;
  225.         (**myDesc).dataFormat = TimeCodeMediaType;
  226.         (**myDesc).timeCodeDef = myTCDef;
  227.         
  228.         //////////
  229.         //
  230.         // set the source identification information
  231.         //
  232.         //////////
  233.  
  234.         // the source identification information for a timecode track is stored
  235.         // in a user data item of type TCSourceRefNameType
  236.         myErr = NewUserData(&myUserData);
  237.         if (myErr == noErr) {
  238.             Handle                             myNameHandle = NULL;
  239.             
  240.             myErr = PtrToHand(&gSrcName[1], &myNameHandle, gSrcName[0]);
  241.             if (myErr == noErr) {
  242.                 myErr = AddUserDataText(myUserData, myNameHandle, TCSourceRefNameType, 1, langEnglish);
  243.                 if (myErr == noErr)
  244.                     TCSetSourceRef(myHandler, myDesc, myUserData);
  245.             }
  246.             
  247.             if (myNameHandle != NULL)
  248.                 DisposeHandle(myNameHandle);
  249.                 
  250.             DisposeUserData(myUserData);
  251.         }
  252.  
  253.         //////////
  254.         //
  255.         // add a sample to the timecode track
  256.         //
  257.         // each sample in a timecode track provides timecode information for a span of movie time;
  258.         // here, we add a single sample that spans the entire movie duration
  259.         //
  260.         //////////
  261.  
  262.         // the sample data contains a frame number that identifies one or more content frames
  263.         // that use the timecode; this value (a long integer) identifies the first frame that
  264.         // uses the timecode
  265.         myFrameHandle = (long **)NewHandle(sizeof(long));
  266.         if (myFrameHandle == NULL)
  267.             goto bail;
  268.         
  269.         myErr = TCTimeCodeToFrameNumber(myHandler, &(**myDesc).timeCodeDef, &myTCRec, *myFrameHandle);
  270.  
  271.         // the data in the timecode track must be big-endian        
  272.         **myFrameHandle = EndianS32_NtoB(**myFrameHandle);
  273.         
  274.         myDuration = GetMovieDuration(theMovie);
  275.         // since we created the track with the same timescale as the movie,
  276.         // we don't need to convert the duration
  277.         
  278.         myErr = AddMediaSample(myMedia, (Handle)myFrameHandle, 0, GetHandleSize((Handle)myFrameHandle), myDuration, (SampleDescriptionHandle)myDesc, 1, 0, 0);
  279.             
  280. bail:
  281.         if (myDesc != NULL)
  282.             DisposeHandle((Handle)myDesc);
  283.             
  284.         if (myFrameHandle != NULL)
  285.             DisposeHandle((Handle)myFrameHandle);
  286.     }
  287.     
  288.     EndMediaEdits(myMedia);    
  289.     myErr = InsertMediaIntoTrack(myTrack, 0, 0, myDuration, fixed1);
  290.     
  291.     //////////
  292.     //
  293.     // create track references from the target track to the timecode track
  294.     //
  295.     //////////
  296.     
  297.     myErr = AddTrackReference(myTypeTrack, myTrack, TimeCodeMediaType, NULL);
  298.     
  299.     return(myErr);
  300. }
  301.  
  302.  
  303. //////////
  304. //
  305. // QTTC_GetTimeCodeOptions 
  306. // Display our options dialog box and get the user's selections.
  307. //
  308. //////////
  309.  
  310. Boolean QTTC_GetTimeCodeOptions (void)
  311. {
  312.     DialogPtr            myDialog = NULL;
  313.     short                myItem = kStdCancelItemIndex;
  314.     ControlHandle        myControl = NULL;
  315.     Rect                myRect;
  316.     GrafPtr                myPort;
  317.     
  318.     GetPort(&myPort);
  319.     
  320.     myDialog = GetNewDialog(kTimeCodeDialogID, NULL, (WindowPtr)-1L);
  321.     if (myDialog == NULL)
  322.         goto bail;
  323.     
  324.     SetDialogDefaultItem(myDialog, kStdOkItemIndex);
  325.     SetDialogCancelItem(myDialog, kStdCancelItemIndex);
  326.  
  327.     myControl = QTTC_GetDItemHandle(myDialog, kItemDisplayTimeCode);
  328.     SetControlValue(myControl, gDisplayTimeCode);
  329.     myControl = QTTC_GetDItemHandle(myDialog, kItemBelowVideo);
  330.     SetControlValue(myControl, gDisplayBelowVideo);
  331.     myControl = QTTC_GetDItemHandle(myDialog, kItemDropFrame);
  332.     SetControlValue(myControl, gDropFrameVal);
  333.     myControl = QTTC_GetDItemHandle(myDialog, kItem24Hour);
  334.     SetControlValue(myControl, g24Hour);
  335.     myControl = QTTC_GetDItemHandle(myDialog, kItemNegOK);
  336.     SetControlValue(myControl, gNegOK);
  337.     myControl = QTTC_GetDItemRect(myDialog, kItemIsNeg, &myRect);
  338.     MacSetPort(myDialog);
  339.     MoveTo(myRect.left + 2, myRect.top + 17);
  340.     MacFrameRect(&myRect);
  341.     TextSize(20);
  342.     if (gIsNeg) 
  343.         DrawString("\p-");
  344.     else
  345.         DrawString("\p+");
  346.     TextSize(12);
  347.  
  348.     myControl = QTTC_GetDItemHandle(myDialog, kItemUseTC);
  349.     SetControlValue(myControl, gUseTimeCode ? 1 : 0);
  350.     myControl = QTTC_GetDItemHandle(myDialog, kItemUseCounter);
  351.     SetControlValue(myControl, gUseTimeCode ? 0 : 1);
  352.  
  353.     QTTC_SetDialogTextNumber(myDialog, kItemTimeScale, gTimeScale);
  354.     QTTC_SetDialogTextNumber(myDialog, kItemFrameDur, gFrameDur);
  355.     QTTC_SetDialogTextNumber(myDialog, kItemNumFrames, gNumFrames);
  356.     QTTC_SetDialogTextNumber(myDialog, kItemHours, gHours);
  357.     QTTC_SetDialogTextNumber(myDialog, kItemMinutes, gMinutes);
  358.     QTTC_SetDialogTextNumber(myDialog, kItemSeconds, gSeconds);
  359.     QTTC_SetDialogTextNumber(myDialog, kItemFrames, gFrames);
  360.  
  361.     QTTC_SetDialogTextNumber(myDialog, kItemCounter, gCounterVal);
  362.     
  363.     QTTC_SetDialogTextString(myDialog, kItemSrcName, gSrcName);
  364.  
  365. noGood:
  366.     do {    
  367.         ModalDialog(NULL, &myItem);
  368.         switch (myItem) {
  369.             case kItemDisplayTimeCode:
  370.                 myControl = QTTC_GetDItemHandle(myDialog, kItemDisplayTimeCode);
  371.                 SetControlValue(myControl, !GetControlValue(myControl));
  372.                 break;
  373.             case kItemBelowVideo:
  374.                 myControl = QTTC_GetDItemHandle(myDialog, kItemBelowVideo);
  375.                 SetControlValue(myControl, !GetControlValue(myControl));
  376.                 break;
  377.             case kItemDropFrame:
  378.                 myControl = QTTC_GetDItemHandle(myDialog, kItemDropFrame);
  379.                 SetControlValue(myControl, !GetControlValue(myControl));
  380.                 break;
  381.             case kItem24Hour:
  382.                 myControl = QTTC_GetDItemHandle(myDialog, kItem24Hour);
  383.                 SetControlValue(myControl, !GetControlValue(myControl));
  384.                 break;
  385.             case kItemNegOK:
  386.                 myControl = QTTC_GetDItemHandle(myDialog, kItemNegOK);
  387.                 SetControlValue(myControl, !GetControlValue(myControl));
  388.                 break;
  389.             case kItemUseTC:
  390.                 myControl = QTTC_GetDItemHandle(myDialog, kItemUseTC);
  391.                 SetControlValue(myControl, 1);
  392.                 myControl = QTTC_GetDItemHandle(myDialog, kItemUseCounter);
  393.                 SetControlValue(myControl, 0);
  394.                 break;
  395.             case kItemUseCounter:
  396.                 myControl = QTTC_GetDItemHandle(myDialog, kItemUseCounter);
  397.                 SetControlValue(myControl, 1);
  398.                 myControl = QTTC_GetDItemHandle(myDialog, kItemUseTC);
  399.                 SetControlValue(myControl, 0);
  400.                 break;
  401.             case kItemIsNeg:
  402.                 gIsNeg = !gIsNeg;
  403.                 MacSetPort(myDialog);
  404.                 MoveTo(myRect.left+2, myRect.top+17);
  405.                 MacFrameRect(&myRect);
  406.                 MacInsetRect(&myRect, 1, 1);
  407.                 EraseRect(&myRect);
  408.                 MacInsetRect(&myRect, -1, -1);
  409.                 TextSize(20);
  410.                 if (gIsNeg) 
  411.                     DrawString("\p-");
  412.                 else
  413.                     DrawString("\p+");
  414.                 TextSize(12);
  415.                 break;
  416.             }
  417.     } while ((myItem != kStdOkItemIndex) && (myItem != kStdCancelItemIndex));
  418.     
  419.     if (myItem == kStdOkItemIndex) {
  420.         myControl = QTTC_GetDItemHandle(myDialog, kItemSrcName);
  421.         GetDialogItemText((Handle)myControl, gSrcName);
  422.     
  423.         myControl = QTTC_GetDItemHandle(myDialog, kItemDisplayTimeCode);
  424.         gDisplayTimeCode = GetControlValue(myControl);
  425.         myControl = QTTC_GetDItemHandle(myDialog, kItemBelowVideo);
  426.         gDisplayBelowVideo = GetControlValue(myControl);
  427.         myControl = QTTC_GetDItemHandle(myDialog, kItemDropFrame);
  428.         gDropFrameVal = GetControlValue(myControl);
  429.         myControl = QTTC_GetDItemHandle(myDialog, kItem24Hour);
  430.         g24Hour = GetControlValue(myControl);
  431.         myControl = QTTC_GetDItemHandle(myDialog, kItemNegOK);
  432.         gNegOK = GetControlValue(myControl);
  433.         myControl = QTTC_GetDItemHandle(myDialog, kItemUseTC);
  434.         gUseTimeCode = (GetControlValue(myControl) != 0);
  435.  
  436.         if (!QTTC_ValidateDialogLong(myDialog, kItemTimeScale, &gTimeScale))
  437.             goto noGood;
  438.         if (!QTTC_ValidateDialogLong(myDialog, kItemFrameDur, &gFrameDur))
  439.             goto noGood;
  440.         if (!QTTC_ValidateDialogLong(myDialog, kItemNumFrames, &gNumFrames))
  441.             goto noGood;
  442.         if (!QTTC_ValidateDialogLong(myDialog, kItemHours, &gHours))
  443.             goto noGood;
  444.         if (!QTTC_ValidateDialogLong(myDialog, kItemMinutes, &gMinutes))
  445.             goto noGood;
  446.         if (!QTTC_ValidateDialogLong(myDialog, kItemSeconds, &gSeconds))
  447.             goto noGood;
  448.         if (!QTTC_ValidateDialogLong(myDialog, kItemFrames, &gFrames))
  449.             goto noGood;
  450.         if (!QTTC_ValidateDialogLong(myDialog, kItemCounter, &gCounterVal))
  451.             goto noGood;
  452.         }
  453.     
  454. bail:
  455.     if (myDialog != NULL)
  456.         DisposeDialog(myDialog);
  457.  
  458.     MacSetPort(myPort);
  459.     
  460.     return(myItem == kStdOkItemIndex);
  461. }
  462.  
  463.  
  464. //////////
  465. //
  466. // QTTC_SetDialogTextNumber 
  467. // Set and highlight the text of a dialog item.
  468. //
  469. //////////
  470.  
  471. void QTTC_SetDialogTextNumber (DialogPtr theDialog, short theItem, long theNumber)
  472. {
  473.     Str255                myText;
  474.  
  475.     NumToString(theNumber, myText);
  476.     SetDialogItemText((Handle)QTTC_GetDItemHandle(theDialog, theItem), myText);
  477.     SelectDialogItemText(theDialog, theItem, 0, 32767);
  478. }
  479.  
  480.  
  481. //////////
  482. //
  483. // QTTC_SetDialogTextString 
  484. // Set and highlight the text of a dialog item.
  485. //
  486. //////////
  487.  
  488. void QTTC_SetDialogTextString (DialogPtr theDialog, short theItem, StringPtr theString)
  489. {
  490.     SetDialogItemText((Handle)QTTC_GetDItemHandle(theDialog, theItem), theString);
  491.     SelectDialogItemText(theDialog, theItem, 0, 32767);
  492. }
  493.  
  494.  
  495. //////////
  496. //
  497. // QTTC_ValidateDialogLong 
  498. // Validate a long value.
  499. //
  500. //////////
  501.  
  502. Boolean QTTC_ValidateDialogLong (DialogPtr theDialog, short theItem, long *theResult)
  503. {
  504.     Str255                myText;
  505.     ControlHandle        myHandle;
  506.     Boolean                IsDigitFound = false;
  507.     short                myIndex;
  508.  
  509.     myHandle = QTTC_GetDItemHandle(theDialog, theItem);
  510.     GetDialogItemText((Handle)myHandle, myText);
  511.  
  512.     for (myIndex = 1; myIndex < myText[0]; myIndex++) {
  513.         if (myText[myIndex] >= '0' && myText[myIndex] <= '9') {
  514.             IsDigitFound = true;
  515.         } else if (IsDigitFound) {
  516.             myText[0] = myIndex - 1;
  517.             break;
  518.         } else if (myText[myIndex] != ' ') {
  519.             SelectDialogItemText(theDialog, theItem, 0, 32767);
  520.             SysBeep(1);
  521.             return(false);
  522.         }
  523.     }
  524.  
  525.     StringToNum(myText, theResult);
  526.     return(true);
  527. }
  528.  
  529.  
  530. //////////
  531. //
  532. // QTTC_GetDItemHandle 
  533. // Get the handle of the specified dialog item.
  534. //
  535. //////////
  536.  
  537. ControlHandle QTTC_GetDItemHandle (DialogPtr theDialog, short theItem)
  538. {
  539.     short                myKind;
  540.     ControlHandle        myHandle;
  541.     Rect                myRect;
  542.  
  543.     GetDialogItem(theDialog, theItem, &myKind, (Handle *)&myHandle, &myRect);
  544.     return(myHandle);
  545. }
  546.  
  547.  
  548. //////////
  549. //
  550. // QTTC_GetDItemRect 
  551. // Get the rectangle surrounding the specified dialog item.
  552. //
  553. //////////
  554.  
  555. ControlHandle QTTC_GetDItemRect (DialogPtr theDialog, short theItem, Rect *theRect)
  556. {
  557.     short                myKind;
  558.     ControlHandle        myHandle;
  559.  
  560.     GetDialogItem(theDialog, theItem, &myKind, (Handle *)&myHandle, theRect);
  561.     return(myHandle);
  562. }
  563.  
  564.  
  565. //////////
  566. //
  567. // QTTC_ShowCurrentTimeCode 
  568. // Show (in an alert box) the timecode value for the current movie time.
  569. //
  570. //////////
  571.  
  572. void QTTC_ShowCurrentTimeCode (Movie theMovie)
  573. {
  574.     MediaHandler        myHandler = NULL;
  575.     HandlerError        myErr = noErr;
  576.     TimeCodeDef            myTCDef;
  577.     TimeCodeRecord        myTCRec;
  578.     
  579.     myHandler = QTTC_GetTimeCodeMediaHandler(theMovie);
  580.     if (myHandler != NULL) {
  581.     
  582.         // get the timecode for the current movie time
  583.         myErr = TCGetCurrentTimeCode(myHandler, NULL, &myTCDef, &myTCRec, NULL);
  584.         if (myErr == noErr) {
  585.             Str255        myString;
  586.             
  587.             myErr = TCTimeCodeToString(myHandler, &myTCDef, &myTCRec, myString);
  588.             if (myErr == noErr)
  589.                 QTTC_ShowStringToUser(myString);
  590.         }
  591.     }
  592. }
  593.  
  594.  
  595. //////////
  596. //
  597. // QTTC_ShowTimeCodeSource
  598. // Show (in an alert box) the timecode source for the specified movie.
  599. //
  600. //////////
  601.  
  602. void QTTC_ShowTimeCodeSource (Movie theMovie)
  603. {
  604.     MediaHandler        myHandler = NULL;
  605.     HandlerError        myErr = noErr;
  606.     UserData            myUserData;
  607.     
  608.     myHandler = QTTC_GetTimeCodeMediaHandler(theMovie);
  609.     if (myHandler != NULL) {
  610.     
  611.         // get the timecode source for the current movie time
  612.         myErr = TCGetCurrentTimeCode(myHandler, NULL, NULL, NULL, &myUserData);
  613.         if (myErr == noErr) {
  614.             Str255        myString = " [No source name!]";
  615.             Handle         myNameHandle = NewHandleClear(0);
  616.             
  617.             GetUserDataText(myUserData, myNameHandle, TCSourceRefNameType, 1, langEnglish);
  618.             if (GetHandleSize(myNameHandle) > 0) {
  619.                 BlockMove(*myNameHandle, &myString[1], GetHandleSize(myNameHandle));
  620.                 myString[0] = GetHandleSize(myNameHandle);
  621.             }
  622.             
  623.             if (myNameHandle != NULL)
  624.                 DisposeHandle(myNameHandle);
  625.             
  626.             QTTC_ShowStringToUser(myString);
  627.             
  628.             DisposeUserData(myUserData);
  629.         }
  630.     }
  631. }
  632.  
  633.  
  634. //////////
  635. //
  636. // QTTC_ShowStringToUser 
  637. // Display a string in an alert box.
  638. //
  639. //////////
  640.  
  641. void QTTC_ShowStringToUser (StringPtr theString)
  642. {
  643.     short         mySavedResFile;
  644.  
  645.     // get the current resource file and set the application's resource file
  646.     mySavedResFile = CurResFile();
  647.     UseResFile(gAppResFile);
  648.  
  649.     ParamText(theString, NULL, NULL, NULL);
  650.     Alert(kTimeCodeAlertID, NULL);
  651.     
  652.     // restore the original resource file
  653.     UseResFile(mySavedResFile);
  654. }
  655.  
  656.  
  657. //////////
  658. //
  659. // QTTC_ToggleTimeCodeDisplay 
  660. // Toggle the current state of timecode display.
  661. //
  662. //////////
  663.  
  664. void QTTC_ToggleTimeCodeDisplay (MovieController theMC)
  665. {
  666.     Movie                myMovie = MCGetMovie(theMC);
  667.     Track                myTrack = NULL;
  668.     MediaHandler        myHandler = NULL;
  669.     long                myFlags = 0L;
  670.     
  671.     // get the (first) timecode track in the specified movie
  672.     myTrack = GetMovieIndTrackType(myMovie, 1, TimeCodeMediaType, movieTrackMediaType);
  673.     if (myTrack != NULL) {
  674.     
  675.         // get the timecode track's media handler
  676.         myHandler = QTTC_GetTimeCodeMediaHandler(myMovie);
  677.         if (myHandler != NULL) {
  678.         
  679.             // toggle the show-timecode flag
  680.             TCGetTimeCodeFlags(myHandler, &myFlags);
  681.             myFlags ^= tcdfShowTimeCode;
  682.             TCSetTimeCodeFlags(myHandler, myFlags, tcdfShowTimeCode);
  683.             
  684.             // toggle the track enabled state
  685.             SetTrackEnabled(myTrack, !GetTrackEnabled(myTrack));
  686.             
  687.             // now tell the movie controller the movie has changed,
  688.             // so that the movie rectangle gets updated correctly
  689.             MCMovieChanged(theMC, myMovie);
  690.         }
  691.     }
  692. }
  693.  
  694.  
  695. //////////
  696. //
  697. // QTTC_GetTimeCodeMediaHandler 
  698. // Get the media handler for the first timecode track in the specified movie.
  699. //
  700. //////////
  701.  
  702. MediaHandler QTTC_GetTimeCodeMediaHandler (Movie theMovie)
  703. {
  704.     Track                myTrack = NULL;
  705.     Media                myMedia = NULL;
  706.     MediaHandler        myHandler = NULL;
  707.     
  708.     // get the (first) timecode track in the specified movie
  709.     myTrack = GetMovieIndTrackType(theMovie, 1, TimeCodeMediaType, movieTrackMediaType);
  710.     if (myTrack != NULL) {
  711.         // get the timecode track's media and media handler
  712.         myMedia = GetTrackMedia(myTrack);
  713.         if (myMedia != NULL)
  714.             myHandler = GetMediaHandler(myMedia);
  715.     }
  716.     
  717.     return(myHandler);
  718. }
  719.  
  720.  
  721. //////////
  722. //
  723. // QTTC_MovieHasTimeCodeTrack
  724. // Determine whether the specified movie contains a timecode track.
  725. // 
  726. //////////
  727.  
  728. Boolean QTTC_MovieHasTimeCodeTrack (Movie theMovie)
  729. {
  730.     return(GetMovieIndTrackType(theMovie, 1, TimeCodeMediaType, movieTrackMediaType) != NULL);
  731. }
  732.